﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;

namespace System
{
    /// <summary>
    /// 枚举扩展
    /// </summary>
    public static class EnumExtension
    {
        /// <summary>
        /// 获得枚举字段的特性(Attribute)，该属性不允许多次定义。
        /// </summary>
        /// <typeparam name="TSource">特性类型</typeparam>
        /// <param name="obj"></param>
        /// <returns>枚举字段的扩展属性</returns>
        public static TSource GetAttribute<TSource>(this object obj) where TSource : Attribute
        {
            FieldInfo field = obj.GetType().GetField(obj.ToString());
            return Attribute.GetCustomAttribute(field, typeof(TSource)) as TSource;
        }

        /// <summary>
        /// 获得Desc特性的值
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string Desc<TSource>(this Enum obj)
        {
            return GetDesc<TSource>(obj);
        }

        internal static string GetDesc<TSource>(object obj)
        {
            var descAttribute = obj.To<TSource>().GetAttribute<DescAttribute>();
            if (descAttribute.IsNotNull()) return descAttribute.Value;

            return string.Empty;
        }
    }

    /// <summary>
    /// 枚举Helper
    /// </summary>
    public class EnumHelper
    {
        /// <summary>
        /// 获得该枚举所有Desc的特性值
        /// </summary>
        /// <typeparam name="TSource">枚举</typeparam>
        /// <returns></returns>
        public static Dictionary<int, string> GetDescs<TSource>()
        {
            var tType = typeof(TSource).ToValueType();

            if (!tType.IsEnum) throw new ArgumentException(string.Format("{0}不是Enum类型", tType.Name));
            return Enum<TSource>.AsEnumerable().ToDictionary(p => p.To<int>(), p => EnumExtension.GetDesc<TSource>(p));
        }

        /// <summary>
        /// 获得对应枚举的Desc特性值
        /// </summary>
        /// <typeparam name="TSource">枚举</typeparam>
        /// <param name="key">枚举对应值</param>
        /// <param name="defaultValue">没有找到对应的Desc特性默认值</param>
        /// <returns></returns>
        public static string GetDesc<TSource>(int key, string defaultValue = "")
        {
            var typeDescs = GetDescs<TSource>();
            var currentType = typeDescs.FirstOrDefault(p => p.Key == key);
            if (typeDescs.IsNotNullAndAny() && currentType.IsNotNull())
                return currentType.Value;

            return defaultValue;
        }
    }

    /// <summary>
    /// TSource 类型枚举列表
    /// </summary>
    /// <typeparam name="TSource">枚举类型</typeparam>
    public class Enum<TSource> : IEnumerable<TSource>
    {
        #region Business Methods
        /// <summary>
        /// 返回类型为 IEnumerable&lt;TSource&gt; 的输入。
        /// </summary>
        /// <returns>类型为 IEnumerable&lt;TSource&gt; 的序列。</returns>
        public static IEnumerable<TSource> AsEnumerable()
        {
            return new Enum<TSource>();
        }
        #endregion

        #region IEnumerable<TSource> 成员
        /// <summary>
        /// 返回一个循环访问集合的枚举数。
        /// </summary>
        /// <returns>可用于循环访问集合的 IEnumerator&lt;TSource&gt; 。</returns>
        public IEnumerator<TSource> GetEnumerator()
        {
            var tType = typeof(TSource).ToValueType();
            var values = Enum.GetValues(tType);

            return values.OfType<TSource>().AsEnumerable().GetEnumerator();
        }
        #endregion

        #region IEnumerable 成员
        /// <summary>
        /// 返回一个循环访问集合的枚举数。
        /// </summary>
        /// <returns>可用于循环访问集合的 IEnumerator 。</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        #endregion

        #region IEnumerable<TSource> 成员
        /// <summary>
        /// 返回一个循环访问集合的枚举数。
        /// </summary>
        /// <returns>可用于循环访问集合的 IEnumerator&lt;TSource&gt; 。</returns>
        IEnumerator<TSource> IEnumerable<TSource>.GetEnumerator()
        {
            return GetEnumerator();
        }
        #endregion
    }

    /// <summary>
    /// 字段或属性的中文解释属性
    /// </summary>
    [Serializable]
    [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
    public class DescAttribute : Attribute
    {
        /// <summary>
        /// 获得字段或属性的中文解释.
        /// </summary>
        /// <value>字段或属性的中文解释.</value>
        public string Value { get; private set; }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="value">字段或属性的解释说明.</param>
        public DescAttribute(string value)
        {
            Value = value;
        }
    }
}
